//---------------------------------------------------------------------------------
// Copyright (c) 2008 VoiceLynx Project
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not be
//        misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//        distribution.
//---------------------------------------------------------------------------------

#include "UI_MainFrame.h"

#include "UI_ProfilesDlg.h"
#include "UI_ServersDlg.h"

#include "VLClientApp.h"

#include "VLCursorSwap.h"

#include <wx/listbase.h>

#define VL_UI_UPDATE_TIMER_ID (5)

BEGIN_EVENT_TABLE(UI_MainFrameExt,UI_MainFrame)
  EVT_TIMER(VL_UI_UPDATE_TIMER_ID, UI_MainFrameExt::OnTimerEvent)
END_EVENT_TABLE()

UI_MainFrameExt::UI_MainFrameExt( wxWindow* parent )
: UI_MainFrame( parent ),
  mUiUpdateTimer(this, VL_UI_UPDATE_TIMER_ID),
  mDisconnectExpected(false),
  mPreviousConnectionState(false)
{
  SetIcon(wxICON(sample));

  mUiUpdateTimer.Start(50, true);
}

void UI_MainFrameExt::OnClose( wxCloseEvent& event )
{
  // Save our current profile/server settings to the registry so we can re-select them
  // when the application starts next time
  wxConfig().Write(VL_CONFIG_KEY_SELECTED_SERVER, m_ddServer->GetStringSelection());
  wxConfig().Write(VL_CONFIG_KEY_SELECTED_PROFILE, m_ddProfile->GetStringSelection());

  // Disconnect from the server
  VL_BEGIN_CORE_CRITICAL_SECTION();
  if (wxGetApp().getClient().isConnected())
  {
    wxGetApp().getClient().disconnect();
    mDisconnectExpected = true;
  }
  VL_END_CORE_CRITICAL_SECTION();

  // Close the main frame (and thus end the application)
  while (wxGetApp().getClient().isConnected())
  {
    wxThread::Sleep(20);
  }
  
  Destroy();
}

void UI_MainFrameExt::OnEditProfiles( wxCommandEvent& event )
{
  // Create and show the profiles dialog
  UI_ProfilesDlgExt profilesDlg(this, mProfiles);
  profilesDlg.ShowModal();

  // Flush the profile settings to the config file
  mProfiles.write(*wxConfig::Get());

  // Force the profile dropdown to update
  RefreshProfiles();
}

void UI_MainFrameExt::OnEditServers( wxCommandEvent& event )
{
  // Create and show the servers dialog
	UI_ServersDlgExt serversDlg(this, mServers);
  serversDlg.ShowModal();

  // Flush the server settings to the config file
  mServers.write(*wxConfig::Get());

  // Force the server dropdown to update
  RefreshServers();
}

void UI_MainFrameExt::OnTreeActivated( wxTreeEvent& event )
{
	// TODO: Implement OnTreeActivated
}

void UI_MainFrameExt::OnTreeContextMenu( wxTreeEvent& event )
{
	// TODO: Implement OnTreeContextMenu
}

void UI_MainFrameExt::OnMuteRx( wxCommandEvent& event )
{
	// TODO: Implement OnMuteRx
}

void UI_MainFrameExt::OnMuteTx( wxCommandEvent& event )
{
	// TODO: Implement OnMuteTx
}

void UI_MainFrameExt::OnConfigure( wxCommandEvent& event )
{
  // Show the config dialog
	UI_ConfigureDlg configureDlg(this);
  configureDlg.ShowModal();

  // TODO: Apply settings
}

void UI_MainFrameExt::OnConnect( wxCommandEvent& event )
{
  VL_BEGIN_CORE_CRITICAL_SECTION();

  if (wxGetApp().getClient().isConnected())
  {
    int result = wxMessageBox(wxT("Are you sure you wish to disconnect?"), wxT("VoiceLynx"), wxYES_NO, this);

    if (result == wxYES)
    {
      wxGetApp().getClient().disconnect();
      mDisconnectExpected = true;
    }
  }
  else
  {
    VLServerSettingsEntry   serverEntry;
    VLProfileSettingsEntry  profileEntry;

    // Get the selected server config entry
	  wxString serverEntryName  = m_ddServer->GetStringSelection();
    bool server  = mServers.getServer(serverEntryName, serverEntry);

    // Get the selected profile config entry
    wxString profileEntryName = m_ddProfile->GetStringSelection();
    bool profile = mProfiles.getProfile(profileEntryName, profileEntry);
    
    // If the user has a valid config and profile setting
    if (server && profile)
    {
      try
      {
        VL_WAIT_CURSOR(this);

        wxGetApp().getClient().setUsername(VLString(profileEntry.username.mb_str()));
        wxGetApp().getClient().setPassword(VLString(profileEntry.password.mb_str()));

        // Tell the core to connect
        wxGetApp().getClient().connectToServer(VLString(serverEntry.host.ToAscii()), serverEntry.port);
      }
      catch (VLENetException e)
      {
        wxString errStr = wxString::Format(
          wxT("Unable to connect to %s on port %d. Please check that the server name and port are correct."), 
          serverEntry.host, serverEntry.port);

        wxMessageBox(errStr, wxT("VoiceLynx"));
      }
    }
    else
    {
      wxMessageBox(wxT("Please select a server and a profile"), wxT("VoiceLynx"));
    }
  }

  UpdateConnectUI();

  VL_END_CORE_CRITICAL_SECTION();
}

//void UI_MainFrameExt::OnUpdateUI( wxUpdateUIEvent& event )
//{
//  m_ledTxVol->SetValue(wxGetApp().getCore().getTxVolume());
//}

void UI_MainFrameExt::OnTimerEvent(wxTimerEvent &event)
{
  // NOTE ON THREAD SAFETY:
  //
  // To mess with core, you will generally need to lock the mutex surrounding
  // the think() main loop. To mess with the UI, no lock is necessary as 
  // this event is serviced using the UI thread

  // Update the tx volume UI element
  if (wxGetApp().getClient().isConnected())
  {
    m_ledTxVol->SetValue(wxGetApp().getCore().getTxVolume());
  }
  else
  {
    m_ledTxVol->SetValue(0.0);
  }
  

  // Update the channels list (list of channels, users, who is talking, etc.)
  UpdateChannelListUI();

  bool isConnected = wxGetApp().getClient().isConnected();

  // Make sure our UI updates based on connection changes
  if (isConnected != mPreviousConnectionState)
  {
    UpdateConnectUI();
  }

  // On a disconnect, check to see if we should pop up an error message
  if (isConnected == false && mPreviousConnectionState)
  {
    if (mDisconnectExpected == false)
    {
      // If we were connected and now we're not, and we didn't expect the disconnect, alert
      // the user
      wxMessageBox(wxT("The connection to the server has been lost"), wxT("VoiceLynx"));
    }
    else
    {
      // We "used" the expected disconnect - the next disconnect is now unexpected
      mDisconnectExpected = false;
    }
  }
  
  mPreviousConnectionState = isConnected;

  // Schedule the UI update to happen in another 50 msec
  mUiUpdateTimer.Start(50, true);
}

void UI_MainFrameExt::RefreshServers(bool isInit)
{
  wxString previousSelection = m_ddServer->GetStringSelection();

  mServers.read(*wxConfig::Get());

  wxArrayString servers;
  mServers.getServerNames(servers);

  m_ddServer->Clear();
  m_ddServer->Append(servers);

  if (isInit)
  {
    previousSelection = wxConfig::Get()->Read(VL_CONFIG_KEY_SELECTED_SERVER, VL_CONFIG_EMPTY_STRING);
  }

  if (previousSelection.IsEmpty() == false)
  {
    m_ddServer->SetStringSelection(previousSelection);
  }
}

void UI_MainFrameExt::RefreshProfiles(bool isInit)
{
  wxString previousSelection = m_ddProfile->GetStringSelection();

  mProfiles.read(*wxConfig::Get());

  wxArrayString profiles;
  mProfiles.getProfileNames(profiles);

  m_ddProfile->Clear();
  m_ddProfile->Append(profiles);

  if (isInit)
  {
    previousSelection = wxConfig::Get()->Read(VL_CONFIG_KEY_SELECTED_PROFILE, VL_CONFIG_EMPTY_STRING);
  }

  if (previousSelection.IsEmpty() == false)
  {
    m_ddProfile->SetStringSelection(previousSelection);
  }

}

void UI_MainFrameExt::UpdateConnectUI()
{
  if (wxGetApp().getClient().isConnected())
  {
    m_btnConnect->SetLabel(wxT("Disconnect"));
    m_ddServer->Disable();
    m_ddProfile->Disable();

    //m_sizerSettings->Show(false);
    //m_sizerInfo->Show(true);
  }
  else
  {
    m_btnConnect->SetLabel(wxT("Connect"));
    m_ddServer->Enable();
    m_ddProfile->Enable();

    //m_sizerSettings->Show(true);
    //m_sizerInfo->Show(false);
  }

  //m_sizerSettings->Layout();
  //m_sizerInfo->Layout();
  m_sizerRoot->Layout();

  this->Refresh();
}

void UI_MainFrameExt::UpdateChannelListUI()
{
  VL_BEGIN_CORE_CRITICAL_SECTION();
  
  const VLUserIdToUserMap &users = wxGetApp().getUsers();

  m_ChannelUsers->DeleteAllItems();

  for (VLUserIdToUserMap::const_iterator iter = users.begin();
    iter != users.end(); ++iter)
  {
    wxString userName(iter->second->userName.c_str(), wxConvUTF8);

    //std::auto_ptr<wxListItem> listItem(new wxListItem());
    //listItem->SetText(userName);

    //m_ChannelUsers->AddChild(listItem.release());
    m_ChannelUsers->AppendItem(m_ChannelUsers->GetRootItem(), userName);
  }

  VL_END_CORE_CRITICAL_SECTION();

  
}

void UI_MainFrameExt::Init()
{
  RefreshServers(true);
  RefreshProfiles(true);
}
